<template>
    <el-dialog v-model="isOpen" title="密度聚类分析" :border="true" width="1200px" align-center>
        <div class="result_show">
            <div class="left">
                <!--图标信息-->
                <div class="eChartContainer" ref="chartRef" />

                <el-divider />

                <!--聚类统计信息-->
                <div class="cluster-stats">
                    <h4>聚类统计信息</h4>
                    <el-descriptions column="2" border>
                        <el-descriptions-item label="聚类数量">{{ clusterCount }}</el-descriptions-item>
                        <el-descriptions-item label="噪声点数量">{{ noiseCount }}</el-descriptions-item>
                        <el-descriptions-item label="总数据点数量">{{ totalPoints }}</el-descriptions-item>
                        <el-descriptions-item label="计算时间">{{ computeTime }}ms</el-descriptions-item>
                        <el-descriptions-item label="特征维度" :span="2">
                            <template #default>
                                {{ featureNames.join("、") }}
                            </template>
                        </el-descriptions-item>
                    </el-descriptions>
                </div>

                <el-divider />

                <div class="cluster-details">
                    <h4>聚类详情</h4>
                    <el-collapse v-if="clusterCount > 0">
                        <el-collapse-item v-for="clusterId in clusterIds" :key="clusterId" :title="`聚类 ${clusterId} (${clusterItems[clusterId].length} 个数据点)`">
                            <el-table :data="clusterItems[clusterId]" border style="width: 100%">
                                <el-table-column v-for="feature in featureNames" :key="feature" :prop="feature" :label="feature" />
                            </el-table>
                        </el-collapse-item>
                    </el-collapse>
                </div>
            </div>

            <div class="right" v-if="noiseCount > 0">
                <h4>噪声点</h4>
                <el-table :data="noiseItems" border max-height="100%">
                    <el-table-column v-for="feature in featureNames" :key="feature" :prop="feature" :label="feature" />
                </el-table>
            </div>
        </div>

        <template #footer>
            <el-button type="primary" @click="isOpen = false">关闭</el-button>
        </template>
    </el-dialog>
</template>

<script setup>
import { computed, nextTick, onUnmounted, ref, watch } from "vue"
import * as echarts                                    from "echarts"

let isOpen = defineModel()
let props  = defineProps([ "result", "originalData" ])

const chartRef    = ref(null)
let chartInstance = ref(null)

// 提取特征名称
const featureNames = computed(() => {
    if(!props.originalData?.listColumn){
        return [ "特征1", "特征2" ]
    }
    return props.originalData.listColumn.map(item => item.key)
})

// 计算统计数据
const clusterCount = computed(() => props.result?.clusterCount || 0)
const noiseCount   = computed(() => props.result?.noiseCount || 0)
const computeTime  = computed(() => props.result?.computeTime || 0)
const totalPoints  = computed(() => props.result?.clusterLabels?.length || 0)

// 获取聚类ID列表
const clusterIds = computed(() => {
    if(!props.result?.clusterLabels || clusterCount.value === 0){
        return []
    }

    const ids = new Set()
    props.result.clusterLabels.forEach(label => {
        if(label !== -2){
            ids.add(label)
        }
    })
    return Array.from(ids).sort((a, b) => a - b)
})

// 按聚类分组的商品数据
const clusterItems = computed(() => {
    const items = {}
    if(!props.originalData?.listAll || !props.result?.clusterLabels){
        return items
    }

    clusterIds.value.forEach(id => {
        items[id] = []
    })

    props.originalData.listAll.forEach((item, index) => {
        const label = props.result.clusterLabels[index]
        if(label !== -2){
            items[label].push(item)
        }
    })

    return items
})

// 噪声点数据
const noiseItems = computed(() => {
    if(!props.originalData?.listAll || !props.result?.clusterLabels){
        return []
    }

    return props.originalData.listAll.filter((_, index) => {
        return props.result.clusterLabels[index] === -2
    })
})

// 监听弹窗显示状态
watch(isOpen, (val) => {
    if(val){
        initChart()
    }
    else{
        cleanupChart()
    }
})

// 清理图表资源
function cleanupChart(){
    if(chartInstance.value){
        chartInstance.value.dispose()
        chartInstance.value = null
    }
    window.removeEventListener("resize", handleResize)
}

// 处理窗口大小变化
function handleResize(){
    if(chartInstance.value){
        chartInstance.value.resize()
    }
}

// 初始化图表
function initChart(){
    nextTick(() => {
        if(!chartRef.value || !props.result || !props.originalData?.listAll){
            return
        }

        // 确保有足够的特征维度用于可视化
        const features = featureNames.value
        if(features.length < 2){
            console.error("至少需要2个特征维度用于可视化")
            return
        }

        // 创建图表实例
        if(!chartInstance.value){
            chartInstance.value = echarts.init(chartRef.value)
        }

        // 准备可视化数据
        const dataPoints = props.originalData.listAll.map((item, index) => {
            const label = props.result.clusterLabels[index] || -2
            return {
                value       : [
                    Number(item[features[0]] || 0),  // X轴：第一个特征值
                    Number(item[features[1]] || 0),   // Y轴：第二个特征值
                ],
                originalItem: item,  // 保存原始数据
                label       : label,
            }
        })

        // 聚类颜色映射
        const clusterColors = [
            "#3498db", "#e74c3c", "#2ecc71", "#f39c12", "#9b59b6",
            "#1abc9c", "#e67e22", "#34495e", "#95a5a6", "#27ae60",
        ]

        // 构建系列数据（按聚类分组）
        const series = []

        // 添加噪声点系列
        series.push({
            name      : "噪声点",
            type      : "scatter",
            data      : dataPoints.filter(p => p.label === -2),
            symbolSize: 15,
            itemStyle : {
                color      : "#f56c6c",
                opacity    : 0.7,
                borderColor: "#fff",
                borderWidth: 1,
            },
            emphasis  : {
                itemStyle: {
                    shadowBlur : 10,
                    shadowColor: "rgba(0, 0, 0, 0.3)",
                    opacity    : 1,
                },
            },
        })

        // 添加每个聚类的系列
        clusterIds.value.forEach((clusterId, index) => {
            series.push({
                name      : `聚类 ${ clusterId }`,
                type      : "scatter",
                data      : dataPoints.filter(p => p.label === clusterId),
                symbolSize: 15,
                itemStyle : {
                    color      : clusterColors[index % clusterColors.length],
                    opacity    : 0.8,
                    borderColor: "#fff",
                    borderWidth: 1,
                },
                emphasis  : {
                    itemStyle: {
                        shadowBlur : 10,
                        shadowColor: "rgba(0, 0, 0, 0.3)",
                        opacity    : 1,
                    },
                },
            })
        })

        // 构建图例数据
        const legendData = [ "噪声点", ...clusterIds.value.map(id => `聚类 ${ id }`) ]

        // 图表配置
        const option = {
            title  : [
                {
                    text     : "DBSCAN密度聚类结果",
                    left     : "center",
                    top      : 10,
                    textStyle: { fontSize: 16, color: "#303133" },
                },
            ],
            tooltip: {
                trigger  : "item",
                padding  : 10,
                formatter: (params) => {
                    const item = params.data.originalItem
                    let html   = `<strong>${ item["SKU 名称"] }</strong><br/>`
                    html += `序号: ${ item["序号"] }<br/>`

                    // 显示所有特征值
                    features.forEach(feature => {
                        html += `${ feature }: ${ item[feature] }<br/>`
                    })

                    // 显示类别信息
                    html += `类别: ${ params.data.label === -2 ? "噪声点" : `聚类 ${ params.data.label }` }`
                    return html
                },
            },
            legend : {
                data        : legendData,
                top         : 40,
                left        : "center",
                type        : "scroll",
                pageIconSize: 12,
                width       : "80%",
            },
            grid   : {
                left        : "8%",
                right       : "5%",
                bottom      : "10%",
                top         : clusterCount.value > 0 ? "15%" : "10%",
                containLabel: true,
            },
            xAxis  : {
                type        : "value",
                name        : features[0],
                nameLocation: "middle",
                nameGap     : 30,
                splitLine   : {
                    lineStyle: { type: "dashed" },
                },
                axisLabel   : {
                    formatter: val => val.toFixed(1),
                },
            },
            yAxis  : {
                type        : "value",
                name        : features[1],
                nameLocation: "middle",
                nameGap     : 50,
                splitLine   : {
                    lineStyle: { type: "dashed" },
                },
                axisLabel   : {
                    formatter: val => val.toFixed(1),
                },
            },
            series : series,
        }

        chartInstance.value.setOption(option)

        // 添加窗口大小变化监听
        window.addEventListener("resize", handleResize)
    })
}

// 组件卸载时清理
onUnmounted(() => {
    cleanupChart()
})
</script>

<style scoped>
.result_show {
    display: flex;
    gap: 10px;
    height: 800px;

    .left {
        flex: 1;
        height: 100%;

        .eChartContainer {
            width: 100%;
            height: 450px;
        }

        .cluster-stats, .cluster-details {
            width: 100%;
        }

        .cluster-details {
            max-height: 400px;
            overflow-y: auto;
            padding-right: 10px;
        }
    }

    .right {
        flex: 1;
        display: flex;
        flex-direction: column;
        height: 100%;
        padding: 0 10px;
    }
}

</style>

